﻿#region Copyright (c) 2000-2013 Developer Express Inc.
/*
{*******************************************************************}
{                                                                   }
{       Developer Express .NET Component Library                    }
{                                                                   }
{                                                                   }
{       Copyright (c) 2000-2013 Developer Express Inc.              }
{       ALL RIGHTS RESERVED                                         }
{                                                                   }
{   The entire contents of this file is protected by U.S. and       }
{   International Copyright Laws. Unauthorized reproduction,        }
{   reverse-engineering, and distribution of all or any portion of  }
{   the code contained in this file is strictly prohibited and may  }
{   result in severe civil and criminal penalties and will be       }
{   prosecuted to the maximum extent possible under the law.        }
{                                                                   }
{   RESTRICTIONS                                                    }
{                                                                   }
{   THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES           }
{   ARE CONFIDENTIAL AND PROPRIETARY TRADE                          }
{   SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS   }
{   LICENSED TO DISTRIBUTE THE PRODUCT AND ALL ACCOMPANYING .NET    }
{   CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY.                 }
{                                                                   }
{   THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED      }
{   FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE        }
{   COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE       }
{   AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT  }
{   AND PERMISSION FROM DEVELOPER EXPRESS INC.                      }
{                                                                   }
{   CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON       }
{   ADDITIONAL RESTRICTIONS.                                        }
{                                                                   }
{*******************************************************************}
*/
#endregion Copyright (c) 2000-2013 Developer Express Inc.

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace UColor.Core.Helpers {
	public class ScreeningReader : StreamReader {
		char[] buffer;
		const string ampString = "&amp;";
		const string gtString = "&gt;";
		const string ltString = "&lt;";
		const string quotString = "&quot;";
		const string aposString = "&apos;";
		const char amp = '&';
		List<string> characters = new List<string>(new string[] { ampString, gtString, ltString, quotString, aposString });
		public ScreeningReader(Stream stream) : base(stream) { }
		public override string ReadToEnd() {
			StringBuilder sb = new StringBuilder();
			char[] buffer = new char[4096];
			while(true) {
				int count = Read(buffer, 0, buffer.Length);
				if(count == 0) break;
				sb.Append(buffer, 0, count);
			}
			return sb.ToString();
		}
		public override int Read(char[] result, int offset, int elementsLeft) {
			if(result == null) return 0;
			int elementsCount = 0;
			int readedByte;
			UpdateCounters(ref elementsLeft, ref elementsCount, offset);
			if(buffer != null && buffer.Length > 0) {
				CopyToResult(buffer, result, ref elementsLeft, ref elementsCount);
				buffer = null;
			}
			while(elementsLeft > 0) {
				readedByte = Read();
				string readedToCompareChars;
				if(readedByte == -1) break;
				if((char)readedByte == amp) {
					UpdateCounters(ref elementsLeft, ref elementsCount, InsertScreeningStringCore(result, IsScreened(result, ref elementsLeft, ref elementsCount, out readedToCompareChars) ? readedToCompareChars : string.Concat(ampString, readedToCompareChars), elementsLeft, elementsCount));
				} else {
					result[elementsCount] = (char)readedByte;
					UpdateCounters(ref elementsLeft, ref elementsCount, 1);
				}
			}
			return elementsCount - offset;
		}
		int InsertScreeningStringCore(char[] result, string securedString, int elementsLeft, int elementsCount) {
			int difference = securedString.Length - elementsLeft;
			int itemsToCopyCount = difference > 0 ? difference : securedString.Length;
			securedString.CopyTo(0, result, elementsCount, itemsToCopyCount);
			int extraBytesCount = securedString.Length - itemsToCopyCount;
			buffer = new Char[extraBytesCount];
			securedString.CopyTo(itemsToCopyCount, buffer, 0, extraBytesCount);
			return itemsToCopyCount;
		}
		void ReadOffset(char[] result, int offset, ref int elementsLeft, ref int elementsCount) {
			if(BaseStream.CanSeek && BaseStream.CanRead) {
				if(BaseStream.Position < offset) {
					offset = (int)BaseStream.Position;
				}
				BaseStream.Seek(-offset, SeekOrigin.Current);
				byte[] byteBuffer = new byte[offset];
				BaseStream.Read(byteBuffer, 0, offset);
				Array.Copy(byteBuffer, result, offset);
				UpdateCounters(ref elementsLeft, ref elementsCount, offset);
			}
		}
		bool IsScreened(char[] result, ref int elementsLeft, ref int elementsCount, out string readedString) {
			StringBuilder charsCollector = new StringBuilder();
			charsCollector.Append((char)Read());
			bool isScreen = false;
			readedString = charsCollector.ToString();
			while(IsLikeScreen(string.Concat(amp, charsCollector.ToString()), out  isScreen)) {
				charsCollector.Append((char)Read());
				readedString = charsCollector.ToString();
				if(isScreen) {
					readedString = string.Concat(amp, readedString);
					return true;
				}
			}
			return false;
		}
		bool IsLikeScreen(string searchFor, out bool isScreen) {
			isScreen = false;
			foreach(string item in characters) {
				if(item.StartsWith(searchFor, StringComparison.Ordinal)) {
					isScreen = item == searchFor;
					return true;
				}
			}
			return false;
		}
		void CopyToResult(char[] fromArray, char[] toArray, ref int elementsLeft, ref int elementsCount) {
			fromArray.CopyTo(toArray, 0);
			UpdateCounters(ref elementsLeft, ref elementsCount, fromArray.Length);
		}
		void UpdateCounters(ref int elementsLeft, ref int elementsCount, int value) {
			elementsLeft -= value;
			elementsCount += value;
		}
	}
}
